﻿using System;
using System.Threading;
using System.Windows;
using System.Windows.Input;

namespace WholeSlideImageViewer
{
    internal class ExportProgressDialogViewModel : ViewModelBase
    {
        private readonly IExportProgress _progress;
        private readonly CancellationTokenSource _cts;

        private bool _isIndeterminate;
        private int _totalTileCount;
        private int _tilesWritten;

        private ICommand? _cancelCommand;

        public event Action? RequestClose;

        private SpinLock _lock = new SpinLock();

        public bool IsIndeterminate { get => _isIndeterminate; set => OnPropertyChanged(nameof(IsIndeterminate), ref _isIndeterminate, value); }
        public int TotalTileCount { get => _totalTileCount; set => OnPropertyChanged(nameof(TotalTileCount), ref _totalTileCount, value); }
        public int TilesWritten { get => _tilesWritten; set => OnPropertyChanged(nameof(TilesWritten), ref _tilesWritten, value); }

        public ICommand CancelCommand => _cancelCommand ??= new RelayCommand(_ => Cancel(), _ => !_cts.IsCancellationRequested);

        [Obsolete("Only use this constructor in design time.", true)]
        public ExportProgressDialogViewModel()
        {
            _progress = null!;
            _cts = new CancellationTokenSource();

            _isIndeterminate = true;
            _totalTileCount = 0;
            _tilesWritten = 0;
        }

        public ExportProgressDialogViewModel(IExportProgress progress, CancellationTokenSource cts)
        {
            _progress = progress;
            _cts = cts;

            _isIndeterminate = true;
            _totalTileCount = 0;
            _tilesWritten = 0;

            progress.TileCountEstimated += OnProgressEstimated;
            progress.TileCountWritten += OnProgressChanged;
            progress.Completed += OnCompleted;
            progress.Canceled += OnCancel;
            progress.Failed += OnFailed;
        }

        private void OnProgressEstimated(int toalTileCount)
        {
            TotalTileCount = toalTileCount;
            TilesWritten = 0;
            IsIndeterminate = false;
        }

        private void OnProgressChanged(int toalTileCount, int tilesWritten)
        {
            bool lockTaken = false;
            try
            {
                _lock.Enter(ref lockTaken);
                TotalTileCount = toalTileCount;
                TilesWritten = tilesWritten;
                IsIndeterminate = false;
            }
            finally
            {
                if (lockTaken)
                {
                    _lock.Exit();
                }
            }
        }

        public void OnCompleted()
        {
            MessageBox.Show("导出成功！");
            RequestClose?.Invoke();
        }

        public void OnCancel()
        {
            RequestClose?.Invoke();
        }

        public void OnFailed()
        {
            MessageBox.Show("导出失败！");
            RequestClose?.Invoke();
        }

        public void Cancel()
        {
            if (!_cts.IsCancellationRequested)
            {
                _cts.Cancel();
            }
        }
    }
}
